#include <SocketUDP.h>
#include <Address.h>
#include <SocketException.h>
#include <sys/types.h>
//#include <sys/socket.h>
#include <string.h>
//#include <sys/uio.h>
//#include <unistd.h>
//#include <netinet/in.h>
//#include <arpa/inet.h>

// Constructores
SocketUDP::SocketUDP(SocketUDP &sudp)
{
   type=sudp.type;
   addr=sudp.addr;
   sd=sudp.sd;
   tc=sudp.tc;
   tc.reset();
   memmove(&saddrl, &sudp.saddrl, sizeof(struct sockaddr_in));
   memmove(&saddrr, &sudp.saddrr, sizeof(struct sockaddr_in));
}

SocketUDP::SocketUDP(Address addr, enum SType type)
{
   this->type=type;
   this->addr=addr;

   sd=socket(PF_INET, SOCK_DGRAM, 0);
   if (sd<0)
      throw SocketException(string("Unable to create socket"));

   switch (type)
   {
    case SOCK_CONNECT: 
      memset(&saddrl, 0, sizeof(struct sockaddr_in));
      memset(&saddrr, 0, sizeof(struct sockaddr_in));
#ifdef BSD
       saddrr.sin_len=sizeof(struct sockaddr_in);
#endif
      saddrr.sin_family=AF_INET;
      saddrr.sin_port=htons(addr.getPort());
      saddrr.sin_addr.s_addr=addr.getIP().toDWord();
      
      break;
      
    case SOCK_SERVE:
      memset(&saddrr, 0, sizeof(struct sockaddr_in));
      memset(&saddrl, 0, sizeof(struct sockaddr_in));
#ifdef BSD
       saddrl.sin_len=sizeof(struct sockaddr_in);
#endif
      saddrl.sin_family=AF_INET;
      saddrl.sin_port=htons(addr.getPort());
      saddrl.sin_addr.s_addr=addr.getIP().toDWord();
      
      if (bind(sd, (struct sockaddr*)&saddrl, sizeof(struct sockaddr_in))<0)
	 throw SocketException(string("Unable to bind socket to ").
			       append(addr.toString()));

      break;
      
   }
}

SocketUDP::~SocketUDP()
{
   close();
}

// Metodes
int SocketUDP::read(void *buf, size_t n)
{
   int b;
   int slen=sizeof(struct sockaddr_in);
   
   if ((b=recvfrom(sd, (char*)buf, n, NULL, (struct sockaddr*)&saddrr, 
		   &slen))<0)
      throw SocketException(string("Error reading from socket"));

//   cout << "saddrr = " << saddr.sin_len
   
   tc.addR(b);
   return b;
}

int SocketUDP::write(void *buf, size_t n)
{
   int b;
   if ((b=sendto(sd, (char*)buf, n, 0, (struct sockaddr*)&saddrr, 
		 sizeof(struct sockaddr_in)))<0)
      throw SocketException(string("Error writing to socket"));
   
   tc.addW(b);
   return b;
}

void SocketUDP::close()
{
   if (sd!=-1)
   {
      closesocket(sd);
      sd=-1;
   }
}
